import anime from 'animejs/lib/anime.es.js'
import { IImagePaint } from 'leafer-ui'
import { edgeConfig } from './config/edgeConfig'
import { clkStore } from './config/runtimeConfig'
import { EdgeKeyType } from './types'
import { uiItems } from './uiItems'
import { logger } from './utils/logger'
import { modules } from './module'

/**
 * 拥有getter和setter的对象
 */
interface IHasGetterAndSetterValue<T> {
    _value: T
    val: () => T
    get: () => Promise<T>
    set: (newVal: T) => Promise<boolean>
}

/**
 * 时钟对象
 */
interface IClk {
    cycles: EdgeKeyType[]
    current: IHasGetterAndSetterValue<number>
    running: boolean
    finishedCycle: number
    step: () => Promise<void>
    rise: () => Promise<void>
    neg: () => Promise<void>
    run: () => Promise<void>
    stop: () => void
}

export const clk: IClk = {
    // 周期
    cycles: ['low', 'rise', 'high', 'neg'],
    // 是否正在运行
    running: false,
    // 当前周期的索引
    current: {
        _value: 0,
        val() {
            return this._value
        },
        async get() {
            return this._value
        },
        async set(v) {
            if (v > 3) {
                v = v - 4
            }
            this._value = v
            return true
        },
    },
    // 已经完成的周期数
    finishedCycle: 0,
    // 执行当前
    async step() {
        // 设置全局仓库中的isAnimating为true
        clkStore.isAnimating = true
        // 获取当前周期的索引
        const currentIndex = this.current.val()
        // 获取当前周期
        const currentCycle = this.cycles[currentIndex]

        const peomiseArr: Promise<void>[] = []

        // 页面中的时钟指针动画
        // 获取当前周期的时间
        let duration = edgeConfig.time[currentCycle]
        let currentCycleWidth = edgeConfig.size[currentCycle]
        if (currentCycle == 'rise') {
            currentCycleWidth =
                edgeConfig.size['rise'] + edgeConfig.size['high']
            duration = edgeConfig.time['rise'] + edgeConfig.time['high']
        } else if (currentCycle == 'neg') {
            currentCycleWidth = edgeConfig.size['neg'] + edgeConfig.size['low']
            duration = edgeConfig.time['neg'] + edgeConfig.time['low']
        }
        // 在该时间内，让时钟指针移动
        if (this.finishedCycle < 4) {
            const clkLine = uiItems.clkLine
            // 如果是第一次执行，则让指针向右移动
            peomiseArr.push(
                anime({
                    targets: clkLine,
                    x: `+=${currentCycleWidth}`,
                    easing: 'linear',
                    duration,
                }).finished
            )
        } else {
            const clkBg = uiItems.clkBg
            const oldFill = clkBg.fill as IImagePaint
            // 如果不是第一次执行，则让背景图向左移动
            peomiseArr.push(
                anime({
                    targets: oldFill.offset,
                    x: `-=${currentCycleWidth}`,
                    easing: 'linear',
                    duration,
                    complete: () => {
                        if (currentIndex + 1 == 4) {
                            oldFill.offset!.x = 0
                        }
                    },
                    update: () => {
                        clkBg.forceUpdate('fill')
                    },
                }).finished
            )
        }

        for (const element of modules) {
            // @ts-ignore
            if (element[currentCycle]) {
                // @ts-ignore
                peomiseArr.push(element[currentCycle]())
            }
        }

        await Promise.all(peomiseArr)
        let step = 1
        if (currentCycle == 'neg' || currentCycle == 'rise') {
            logger.snapshot(currentCycle)
            step = 2
        }
        // 指向下一个周期
        this.finishedCycle += step
        await this.current.set(currentIndex + step)
        clkStore.isAnimating = false
        return
    },
    // 手动触发一次上升沿
    async rise() {
        clkStore.isAnimating = true
        const peomiseArr: Promise<void>[] = []

        for (const element of modules) {
            // @ts-ignore
            if (element['rise']) {
                // @ts-ignore
                peomiseArr.push(element['rise']())
            }
        }
        await Promise.all(peomiseArr)
        logger.snapshot('rise')
        clkStore.isAnimating = false
        return
    },
    // 手动触发一次下降沿
    async neg() {
        clkStore.isAnimating = true
        const peomiseArr: Promise<void>[] = []

        for (const element of modules) {
            // @ts-ignore
            if (element['neg']) {
                // @ts-ignore
                peomiseArr.push(element['neg']())
            }
        }
        await Promise.all(peomiseArr)
        logger.snapshot('neg')
        clkStore.isAnimating = false
        return
    },
    // 运行
    async run() {
        clkStore.isRunning = true
        this.running = true
        await this.step()
        if (this.running) {
            this.run()
        }
    },
    // 停止
    stop() {
        clkStore.isRunning = false
        this.running = false
    },
}

// @ts-ignore
window.clk = clk
